#ifndef PAGE_TABLE_H
#define PAGE_TABLE_H

#include <Types.h>
#include <BuddyAllocator.h>
#include <asm.h>
#include <kstdio.h>

#define PAGE_TABLE_SIZE		1024
#define KERNEL_PAGE		0

#define PG_DIR_SHIFT	22
#define PG_DIR_MASK		0x3FFFFF
#define PG_TLB_SHIFT	12
#define PG_TLB_MASK	0x3FF000
#define PG_OFFSET_MASK	0xFFF

#define _pgd_i(addr)	\
	((addr) >> PG_DIR_SHIFT)

#define _pmd_i(addr)	\
	(((addr) & PG_DIR_MASK) >> PG_TLB_SHIFT)


#define NOT_PRESENT		0
#define USER_PAGE		0

#define PG_ADDR_MASK	0xFFF

//Копировать только пространство ядра
#define PT_COPY_KS	0
//Копировать все адресное пространство
#define PT_COPY_AS	1
//Пометить страницы пользовательского пространства только для чтения
#define PT_MARK_RO	2

#define PTE_P	0
#define PTE_RW	1
#define PTE_US	2

class PageTable{
	uint32	height;
	public:
		page_t	*root;
		
		PageTable(uint32 h, page_t *ptr);
		PageTable(PageTable *from_tlb, uint32 flag);
		inline uint32 getHeight(){return height;}
		void mapPage(addr_t addr, Frame *frm, uint32 flags);
		void enable_paging(addr_t gpd){
			kprintf("1\n");
			asm("pushfl; cli;");
			asm(".code32 \
				movl %0, %%cr3;"::"r"(gpd):"%eax");
			kprintf("2\n");
			asm(".code32 \
				mov %cr0, %eax;	\
 				bts	$31, %eax; 	\
				mov %eax, %cr0;");
			asm("jmp 1f");
			asm("1:nop");
			asm("popfl");
			kprintf("3\n");
		}
		
		void flushTLB(){
			asm("movl %cr3, %eax");
			asm("movl %eax, %cr3");
		}
		
		void enablePaging(){
			asm("pushfl; cli;");
			asm(".code32 \
				movl %0, %%cr3;"::"r"(_pa(root)):"%eax");
		
			asm(".code32 \
				mov %cr0, %eax;	\
 				bts	$31, %eax; 	\
				mov %eax, %cr0;");
			asm("jmp 1f");
			asm("1:nop");
			asm("popfl");
		}
};

extern PageTable *globalPageDir;


#endif /* PAGE_TABLE_H */

